package com.java.simple.study.juc.pattern;

import com.java.simple.study.tool.Sleeper;
import lombok.extern.slf4j.Slf4j;

import java.util.Arrays;
import java.util.List;

/**
 * @author zhoujl
 * @date 2022/5/9 16:33
 * @desc
 */
@Slf4j(topic = "c.TestGuardedObject")
public class TestGuardedObjectV2 {

    public static void main(String[] args) {
        GuardedObjectV2 guardedObject = new GuardedObjectV2();
        new Thread(() -> {
            Sleeper.sleep(1);
            guardedObject.complete(null);
            Sleeper.sleep(1);
            guardedObject.complete(Arrays.asList("a", "b", "c"));
        }).start();
        // 测试非超时
        //Object response = guardedObject.get(2500);
        // 测试超时
        Object response = guardedObject.get(1500);
        if (response != null) {
            log.debug("get response size:[{}]", ((List<String>) response).size());
        } else {
            log.debug("cant get response");
        }
    }


}

@Slf4j(topic = "c.GuardedObjectV2")
class GuardedObjectV2 {
    private Object response;
    private final Object lock = new Object();

    public Object get(long mills) {
        synchronized (lock) {
            // 1. 记录最初时间
            long begin = System.currentTimeMillis();
            // 2. 已经经历的时间
            long timePassed = 0;
            while (response == null) {
                // 4. 假设mills是1000 结果在400时唤醒了，那么还有600要等
                long waitTime = mills - timePassed;
                log.debug("waitTime:{}", waitTime);
                if (waitTime <= 0) {
                    log.debug("break...");
                    break;
                }
                try {
                    lock.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 3. 如果提前被唤醒 这时已经经历的时间为400
                timePassed = System.currentTimeMillis() - begin;
                log.debug("timePassed:{},object is null:{}", timePassed, response == null);
            }
            return response;
        }
    }

    public void complete(Object response) {
        synchronized (lock) {
            this.response = response;
            lock.notifyAll();
        }
    }

}
